/**
 * 
 */
package com.gr.staffpm.google.utils;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.commons.lang.math.RandomUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.Person;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.calendar.ColorProperty;
import com.google.gdata.data.calendar.HiddenProperty;
import com.google.gdata.data.calendar.TimeZoneProperty;
import com.google.gdata.data.extensions.EventEntry;
import com.google.gdata.data.extensions.ExtendedProperty;
import com.google.gdata.data.extensions.When;
import com.google.gdata.data.extensions.Where;
import com.gr.staffpm.datatypes.Task;
import com.gr.staffpm.datatypes.User;
import com.gr.staffpm.security.service.UserService;


/**
 * @author Graham Rhodes 31 Mar 2011 12:51:56
 */
public class GCalUtils {

    private static final Logger log = LoggerFactory.getLogger(GCalUtils.class);

    public static void addTaskToGCal(Task newTask, UserService userService, User currUser) {
        try {
            if (checkCreateStaffPMCalendarExists(userService, currUser)) {
                currUser = userService.getUser(currUser.getUserId());
                URL eventFeedUrl = new URL("https://www.google.com/calendar/feeds" + currUser.getGcalId() + "/private/full");
                EventEntry newEntry = new EventEntry();
                newEntry.setTitle(new PlainTextConstruct(newTask.getName() + " is due"));
                newEntry.setContent(new PlainTextConstruct(newTask.getDescription()));

                newEntry.getAuthors().add(new Person(newTask.getAssignee().getFullName()));
                com.google.gdata.data.DateTime start = new com.google.gdata.data.DateTime(new DateTime(newTask.getDueDate()).plusDays(1).toDate());
                start.setDateOnly(true);
                When eventTimes = new When();
                eventTimes.setStartTime(start);
                eventTimes.setEndTime(start);
                newEntry.addTime(eventTimes);

                CalendarService service = new CalendarService("GrahamRhodes-StaffPM-0.1-SNAPSHOT");
                service.setUserToken(currUser.getGcalAuth());
                service.insert(eventFeedUrl, newEntry);
            }
        } catch (Exception e) {
            log.error("Exception getting calendars from google.", e);
        }
    }

    public static List<com.gr.staffpm.pages.schedule.model.Event> getAndProcessGcalEvents(UserService userService, DateTime start, DateTime end) {
        List<com.gr.staffpm.pages.schedule.model.Event> gcalEvents = new ArrayList<com.gr.staffpm.pages.schedule.model.Event>();
        try {
            com.google.gdata.data.DateTime startTime = new com.google.gdata.data.DateTime(start.toDate());
            com.google.gdata.data.DateTime endTime = new com.google.gdata.data.DateTime(end.toDate());
            URL eventFeedUrl = new URL("https://www.google.com/calendar/feeds/default/private/full");
            CalendarQuery query = new CalendarQuery(eventFeedUrl);
            query.setMinimumStartTime(startTime);
            query.setMaximumStartTime(endTime);
            //query.setStringCustomParameter("fields", "entry(title,gd:when)");
            query.setStringCustomParameter("singleevents", "true");
            query.setStringCustomParameter("showdeleted", "false");

            CalendarService service = new CalendarService("GrahamRhodes-StaffPM-0.1-SNAPSHOT");
            service.setUserToken(userService.getCurrentUser().getGcalAuth());
            // Send the request and receive the response:
            CalendarEventFeed resultFeed = service.query(query, CalendarEventFeed.class);

            for (int i = 0; i < resultFeed.getEntries().size(); i++) {
                CalendarEventEntry entry = resultFeed.getEntries().get(i);
                //log.info("\t" + entry.getTitle().getPlainText());
                if (!entry.getTimes().isEmpty()) {
                    com.gr.staffpm.pages.schedule.model.Event evt = new com.gr.staffpm.pages.schedule.model.Event();
                    When when = entry.getTimes().get(0);
                    DateTime startDate = new DateTime(when.getStartTime().getValue());
                    DateTime endDate = new DateTime(when.getEndTime().getValue());
                    Period p = new Period(startDate, endDate, PeriodType.days());
                    boolean isAllDay = when.getStartTime().isDateOnly();
                    evt.setAd(isAllDay);
                    evt.setStart(startDate);
                    evt.setCid(2);
                    evt.setId(RandomUtils.nextInt(1000));
                    evt.setEnd(isAllDay ? startDate.plusDays(p.getDays() - 1) : new DateTime(when.getEndTime().getValue()));
                    evt.setTitle(entry.getTitle().getPlainText());
                    gcalEvents.add(evt);
                }
            }
        } catch (Exception e) {
            log.error("Exception getting calendars from google.", e);
        }
        return gcalEvents;
    }

    public static boolean checkCreateStaffPMCalendarExists(UserService userService, User currUser) {
        try {
            if (currUser.getGcalId() == null) {
                // Create a CalenderService and authenticate
                CalendarService service = new CalendarService("GrahamRhodes-StaffPM-0.1-SNAPSHOT");
                service.setUserToken(currUser.getGcalAuth());

                // Send the request and print the response
                URL feedUrl = new URL("https://www.google.com/calendar/feeds/default/owncalendars/full");
                CalendarFeed resultFeed = service.getFeed(feedUrl, CalendarFeed.class);

                for (int i = 0; i < resultFeed.getEntries().size(); i++) {
                    CalendarEntry entry = resultFeed.getEntries().get(i);
                    if (entry.getTitle().getPlainText().equals("StaffPM Tasks")) {
                        currUser.setGcalId(entry.getId().substring(entry.getId().lastIndexOf("/")));
                        userService.addOrUpdateUser(currUser);
                        return true;
                    }
                }
                // Create the calendar
                CalendarEntry calendar = new CalendarEntry();
                calendar.setTitle(new PlainTextConstruct("StaffPM Tasks"));
                calendar.setSummary(new PlainTextConstruct("This calendar contains staffpm tasks."));
                calendar.setTimeZone(new TimeZoneProperty(DateTimeZone.getDefault().getID()));
                calendar.setHidden(HiddenProperty.FALSE);
                calendar.setColor(new ColorProperty("#2952A3"));
                calendar.addLocation(new Where("", Locale.getDefault().getDisplayCountry(), Locale.getDefault().getDisplayCountry()));
                ExtendedProperty staffpm = new ExtendedProperty();
                staffpm.setName("staffpm");
                staffpm.setValue("true");
                calendar.setExtension(staffpm);

                // Insert the calendar
                URL postUrl = new URL("https://www.google.com/calendar/feeds/default/owncalendars/full");
                CalendarEntry cal = service.insert(postUrl, calendar);
                currUser.setGcalId(cal.getId().substring(cal.getId().lastIndexOf("/")));
                userService.addOrUpdateUser(currUser);
                return true;
            } else
                return true;
        } catch (Exception e) {
            log.error("Exception checking for staffpm calendar.", e);
        }
        return false;
    }
}
